package com.sunchangpeng.gemini.task;

import com.sunchangpeng.gemini.component.AbstractLifeCycle;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

public class TaskContainer extends AbstractLifeCycle {
    private SchedulerFactory schedulers;

    @Override
    protected void doStart() throws Exception {
        this.schedulers = new StdSchedulerFactory();
        this.schedulers.getScheduler().start();
    }

    public boolean scheduleJob(TaskDetail taskDetail) {
        try {
            return createQuartzJob(taskDetail);
        } catch (SchedulerException e) {
            return false;
        }
    }

    public boolean createQuartzJob(TaskDetail taskDetail) throws SchedulerException {
        JobKey jobKey = buildJobKey(taskDetail);
        JobDataMap jobData = buildJobData(taskDetail);

        JobDetail quartzJob = newJob(TaskAgent.class)
                .withIdentity(jobKey)
                .usingJobData(jobData)
                .build();


        CronScheduleBuilder scheduleBuilder = cronSchedule(taskDetail.getCron());
        if (taskDetail.isMisfire()) {
            scheduleBuilder.withMisfireHandlingInstructionDoNothing();
        } else {
            scheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
        }

        Trigger trigger = newTrigger()
                .withIdentity(buildTriggerKey(taskDetail))
                .withSchedule(scheduleBuilder)
                .build();

        // start scheduling the job
        schedulers.getScheduler().scheduleJob(quartzJob, trigger);

        return Boolean.TRUE;
    }

    private JobKey buildJobKey(TaskDetail taskDetail) {
        return buildJobKey(taskDetail.getAppName(), taskDetail.getClazz());
    }

    private JobKey buildJobKey(String appName, String jobClass) {
        return JobKey.jobKey(jobClass, appName);
    }

    private JobDataMap buildJobData(TaskDetail taskDetail) {
        JobDataMap jobData = new JobDataMap();
        jobData.put("taskDetail", taskDetail);
        return jobData;
    }

    private TriggerKey buildTriggerKey(TaskDetail taskDetail) {
        return buildTriggerKey(taskDetail.getAppName(), taskDetail.getClazz());
    }

    private TriggerKey buildTriggerKey(String appName, String jobClass) {
        return TriggerKey.triggerKey(jobClass, appName);
    }
}
